package net.borderwars.robots;

import net.borderwars.map.*;

import java.awt.*;
import java.util.LinkedList;

/**
 * @author Eric
 *         Date: Feb 2, 2003
 *         Time: 9:19:17 PM
 */
public class Robot extends AbstractMovable implements Movable {

    private int direction = 0;
    private int speed;
    public int numMissles = 0;
    private int damage;
    private long damageDealt;

    public int getLastScan () {
        return lastScan;
    }

    private int lastScan = -1;

    public int getLastResoultion () {
        return lastResoultion;
    }

    private int lastResoultion = 0;

    public int sin (int degree) {
        return super.sin (degree);    //To change body of overridden methods use File | Settings | File Templates.
    }

    public int cos (int degree) {
        return super.cos (degree);    //To change body of overridden methods use File | Settings | File Templates.
    }

    public int tan (int degree) {
        return super.tan (degree);    //To change body of overridden methods use File | Settings | File Templates.
    }

    public int rand (int limit) {
        return super.rand (limit);    //To change body of overridden methods use File | Settings | File Templates.
    }

    public int sqrt (int number) {
        return super.sqrt (number);    //To change body of overridden methods use File | Settings | File Templates.
    }

    public int atan (int ratio) {
        return super.atan (ratio);    //To change body of overridden methods use File | Settings | File Templates.
    }

    public int scan (int degree, int resolution) {
        degree = degree % 360;
        lastScan = degree;
        lastResoultion = resolution;
        int closest = Integer.MAX_VALUE;
        Mappable closeRobot = null;

        int end = (degree + resolution) % 360;
        for (Mappable other : map.getMappables ()) {
            if (other != this) {
                int mang = angleTo (other);
                //int mang = 180 + 180 * (xx > loc_x()) + atan(100000 * (loc_y() - yy) / (loc_x() - xx));
                // int mang = (int) Math.toDegrees(Math.atan((double) ((this.y - other.loc_y()) / (this.x - other.loc_x()))));
                for (int start = (degree - resolution) % 360; start < end; start++) {
                    if (start % 360 == mang) {
                        int dist = 0;
                        //try {
                        dist = calcDistance (this.loc_x (), this.loc_y (), other.loc_x (), other.loc_y ());
//                        } catch (ArithmeticException encoder) {
//                            dist = 10000;
//                        }
                        if (dist < closest) {
                            closest = dist;
                            closeRobot = other;
                        }
                    }
                }
            }
        }

        if (closest != Integer.MAX_VALUE) {
            //   System.out.println(this + " scanned " + closeRobot + " scanning " + degree + " at range " + closest);
            return (closest);
        }
        return (0);

    }

    /**
     * The scan() function invokes the robot's scanner, at a specified degree and resolution.
     * scan() returns 0 if no robots are within the scan range or a positive integer representing
     * the range to the closest robot. Degree should be within the range 0-359, otherwise degree is
     * forced into 0-359 by a modulo 360 operation, and made positive if necessary. Resolution controls the scanner's sensing resolution, up to +/- 10 degrees.
     * <p/>
     * Examples:
     * range = scan(45,0); // scan 45, with no variance
     * range = scan(365,10); // scans the range from 355 to 15
     *
     * @param degree
     * @return
     */

//    public int scan(int degree, int resolution) {
//        degree = degree % 360;
//        int start = degree - resolution;
//        int end = degree + resolution;
//
//        int soFar = Integer.MAX_VALUE;
//
//        while (start <= end) {
//            int thisTime = scan(start);
//            if (thisTime < soFar) {
//                soFar = thisTime;
//            }
//            start++;
//        }
//        if (soFar == Integer.MAX_VALUE) {
//            return (0);
//        }
//        return (soFar);
//    }
//
//    private int scan(int degree) {
//
//        degree %= 360;
//        System.out.println("pscan " + degree);
//        double rise = Math.sin(Math.toRadians((double) degree));
//        double run = Math.cos(Math.toRadians((double) degree));
//        int distance = 1;
//        while (distance < 700) {
//            int cx = (int)  (loc_x() + (run * distance));
//            int cy = (int)  (loc_y() + (rise * distance));
//            if (cx >= 0 && cx < map.getWidth())
//                if (cy >= 0 && cy < map.getHeight()) {
//                    Object o = map.getMappable(cx, cy);
//                    if (o != null) {
//                        return (distance);
//                    }
//                }
//            distance++;
//        }
//        return (0);
//    }

    int lastFire = 0;

    public boolean cannon (int degree, int range) {
        lastScan = -1;
        if (numMissles >= 2) { // sorry reloading
            return (false);
        }
        numMissles++;
        // System.out.println("fire " + degree + " " + range);
//        Missle m = new Missle(x, y, degree, range, vm.getCurrentTick(), this);
//        map.add(m);
        lastFire = degree;

        // TODO: get it on the event queue

        return (true);
    }

    public void drive (int degree, int speed) {
        degree %= 360;
        lastScan = -1;
        this.speed = Math.min (100, speed);
        direction = degree;
    }

    public int damage () {
        return (damage);
    }

    public int speed () {
        return (speed);
    }

    public int direction () {
        return direction;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public void setX (int nx) {
        this.x = nx;
    }

    public void setY (int ny) {
        this.y = ny;
    }

    public void setSpeed (int i) {
        this.speed = i;
    }

    public Location getLocation () {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public Velocity getVelocity () {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public Location getDestination () {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public int loc_x () {
        return (x);
    }

    public int loc_y () {
        return (y);
    }

    public void draw (int x, int y, Graphics g) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void draw (int x, int y, Graphics g, MapPane mp) {
        // g.setColor(Color.GREEN);
        String name = g.getFont ().getName ();
        g.setFont (new Font (name, Font.BOLD, 20));
        g.setColor (Color.YELLOW);
        g.drawString ("" + id, x - 10, y - 10);
        if (lastScan != -1) {
            g.setColor (Color.GREEN);

            int end = (lastScan + lastResoultion) % 360;
            int start = (lastScan - lastResoultion) % 360;

            int sx = (int) (Math.cos (Math.toRadians (start)) * 700);
            int sy = (int) (Math.sin (Math.toRadians (start)) * 700);
            int ex = (int) (Math.cos (Math.toRadians (end)) * 700);
            int ey = (int) (Math.sin (Math.toRadians (end)) * 700);

            sx += x;
            ex += x;
            sy += y;
            ey += y;

            sx = mp.transX (sx);
            ex = mp.transX (ex);
            sy = mp.transY (sy);
            ey = mp.transY (ey);
            // System.out.println(lastScan + " " + Math.sin(Math.toRadians(lastScan)) );

            //   g.drawOval(x-175,y-175,350,350);

            prettyLine (g, x, y, sx, sy);
            prettyLine (g, x, y, ex, ey);
            prettyLine (g, sx, sy, ex, ey);
        }

//        Font f = g.getFont();
//        Font newFont = new Font(f.getName(), f.getStyle(), f.getCapacity());
//        g.setFont(newFont);
//        for(int xx =0; xx<=1000; xx+=200) {
//            for(int yy=0; yy<=1000; yy+=200) {
//                g.setColor(Color.RED);
//                g.drawOval(xx-1, yy-1, 2, 2);
//                g.setColor(Color.GREEN);
//                g.drawString(xx+","+yy, mp.transX(xx),mp.transY(yy));
//
//            }
//        }
//        g.setFont(f);

        //  g.drawArc(x, y, 10, 10, lastScan - 20, 40);

        //g.fillRect(x, y, 4, 4);
    }

    private void prettyLine (Graphics g, int x, int y, int xx, int yy) {
        g.drawLine (x, y, xx, yy);
        g.drawLine (x, y, xx - 1, yy - 1);
        g.drawLine (x, y, xx + 1, yy + 1);

    }

    public void gotHit (int dmg) {
        damage += dmg;
    }

    LinkedList<String> problems = new LinkedList<String> ();

    protected void reportProblem (String s) {
        problems.addLast (s);
    }

    public String toString () {
        return "Robot{" + "direction=" + direction + ", speed=" + speed + ", damage=" + damage + ", x=" + x + ", y=" + y + ", id=" + id + "}";
    }

    public void println (String s) {
        System.out.println (s);
    }

    public void printInt (int heading) {
        System.out.println (this.getVM ().getName () + " " + heading);
    }

    public void incrementDamageDealt (long inc) {
        damageDealt += inc;
    }

    public long getDamageDealt () {
        return (damageDealt);
    }
}
